a tool for shared writing and social publishing
1import { z } from "zod";
2import { makeRoute } from "../lib";
3import type { Env } from "./route";
4import { AtUri } from "@atproto/syntax";
5import { getFactsFromHomeLeaflets } from "./getFactsFromHomeLeaflets";
6import { normalizeDocumentRecord } from "src/utils/normalizeRecords";
7import { ids } from "lexicons/api/lexicons";
8
9export type GetPublicationDataReturnType = Awaited<
10 ReturnType<(typeof get_publication_data)["handler"]>
11>;
12export const get_publication_data = makeRoute({
13 route: "get_publication_data",
14 input: z.object({
15 did: z.string(),
16 publication_name: z.string(),
17 }),
18 handler: async (
19 { did, publication_name },
20 { supabase }: Pick<Env, "supabase">,
21 ) => {
22 let pubLeafletUri;
23 let siteStandardUri;
24 if (/^(?!\.$|\.\.S)[A-Za-z0-9._:~-]{1,512}$/.test(publication_name)) {
25 pubLeafletUri = AtUri.make(
26 did,
27 ids.PubLeafletPublication,
28 publication_name,
29 ).toString();
30 siteStandardUri = AtUri.make(
31 did,
32 ids.SiteStandardPublication,
33 publication_name,
34 ).toString();
35 }
36 let { data: publication, error } = await supabase
37 .from("publications")
38 .select(
39 `*,
40 documents_in_publications(documents(
41 *,
42 comments_on_documents(count),
43 document_mentions_in_bsky(count)
44 )),
45 publication_subscriptions(*, identities(bsky_profiles(*))),
46 publication_domains(*),
47 leaflets_in_publications(*,
48 documents(*),
49 permission_tokens(*,
50 permission_token_rights(*),
51 custom_domain_routes!custom_domain_routes_edit_permission_token_fkey(*)
52 )
53 )`,
54 )
55 .or(`name.eq."${publication_name}", uri.eq."${pubLeafletUri}", uri.eq."${siteStandardUri}"`)
56 .eq("identity_did", did)
57 .single();
58
59 let leaflet_data = await getFactsFromHomeLeaflets.handler(
60 {
61 tokens:
62 publication?.leaflets_in_publications.map(
63 (l) => l.permission_tokens?.root_entity!,
64 ) || [],
65 },
66 { supabase },
67 );
68
69 // Pre-normalize documents from documents_in_publications
70 const documents = (publication?.documents_in_publications || [])
71 .map((dip) => {
72 if (!dip.documents) return null;
73 const normalized = normalizeDocumentRecord(dip.documents.data, dip.documents.uri);
74 if (!normalized) return null;
75 return {
76 uri: dip.documents.uri,
77 record: normalized,
78 indexed_at: dip.documents.indexed_at,
79 data: dip.documents.data,
80 commentsCount: dip.documents.comments_on_documents[0]?.count || 0,
81 mentionsCount: dip.documents.document_mentions_in_bsky[0]?.count || 0,
82 };
83 })
84 .filter((d): d is NonNullable<typeof d> => d !== null);
85
86 // Pre-filter drafts (leaflets without published documents, not archived)
87 const drafts = (publication?.leaflets_in_publications || [])
88 .filter((l) => !l.documents)
89 .filter((l) => !(l as { archived?: boolean }).archived)
90 .map((l) => ({
91 leaflet: l.leaflet,
92 title: l.title,
93 permission_tokens: l.permission_tokens,
94 // Keep the full leaflet data for LeafletList compatibility
95 _raw: l,
96 }));
97
98 return {
99 result: {
100 publication,
101 documents,
102 drafts,
103 leaflet_data: leaflet_data.result,
104 },
105 };
106 },
107});